package am.fp
{
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.Sprite;
  import flash.geom.Matrix;
  import flash.printing.PrintJob;
  import flash.printing.PrintJobOptions;
  import flash.printing.PrintJobOrientation;
  
  import am.fp.Document;
  import am.fp.FPDispatcher;
  import am.fp.events.PrintEvent;
  import am.fp.events.ZoomEvent;

  /**
   * Print controller.
   */
  public class PrintManager
  {
    protected static const MARGIN: int = 20;
    
    protected static var m_instance: PrintManager;
    protected var m_currentZoom: Number;
    protected var m_pageNum: Array;
    protected var m_pj: PrintJob;
    
    public function PrintManager(enforcer: SingletonEnforcer)
    {
      if (enforcer == null)
        throw new Error("This class is a singleton so it can't be instantiated");
        
      // connect listener
      FPDispatcher.instance.addEventListener(PrintEvent.START, onStart, false, 0, true);
    }
    
    public static function init(): PrintManager
    {
      if (m_instance == null)
        m_instance = new PrintManager(new SingletonEnforcer);
      return m_instance;
    }
    
    /**
     * Start print job.
     */
    protected function onStart(e: PrintEvent): void
    {
      m_pj = new PrintJob();
      if (m_pj.start())
      {
        m_currentZoom = Document.instance.currentZoom;
        m_pageNum = e.pageNum;
        FPDispatcher.instance.addEventListener(ZoomEvent.CHANGE, onChangeZoom, false, 0, true);
        FPDispatcher.instance.dispatchEvent(new ZoomEvent(ZoomEvent.CHANGE, 1));
      }
      else
      {
        FPDispatcher.instance.dispatchEvent(new PrintEvent(PrintEvent.STATUS, null, PrintEvent.STATUS_CANCELED));
      }
    }
    
    /**
     * Add into the print job each page to be printed after the zoom was updated.
     */
    protected function onChangeZoom(e: ZoomEvent): void
    {
      FPDispatcher.instance.removeEventListener(ZoomEvent.CHANGE, onChangeZoom, false);
      
      var doc: Document = Document.instance;
      var scale: Number = Math.min((m_pj.pageWidth - 2*MARGIN) / doc.pageWidth, (m_pj.pageHeight - 2*MARGIN) / doc.pageHeight);
      var currentScale: Number;
      var opt: PrintJobOptions = new PrintJobOptions(true);
      var page: Sprite;
      
      try
      {
        // add each page
        for (var i: int = 0; i < m_pageNum.length; i++)
        {
          page = doc.getPage(m_pageNum[i]).content;
          if (page)
          {
            // TODO: handle landscape support ?
            // if (m_pj.orientation == PrintJobOrientation.LANDSCAPE)
            
            currentScale = page.scaleX;
            page.scaleX = page.scaleY = scale;
            m_pj.addPage(page, null, opt);
            page.scaleX = page.scaleY = currentScale;
          }
        }
          
        // send print job
        m_pj.send();
        
        // dispatch print end notification
        FPDispatcher.instance.dispatchEvent(new PrintEvent(PrintEvent.STATUS, null, PrintEvent.STATUS_FINISHED));
      }
      catch (error:Error)
      {
        trace(error.message);
        FPDispatcher.instance.dispatchEvent(new PrintEvent(PrintEvent.STATUS, [error.message], PrintEvent.STATUS_FAILED));
      }
      
      FPDispatcher.instance.dispatchEvent(new ZoomEvent(ZoomEvent.CHANGE, m_currentZoom));
      m_pj = null;
    }
  }
}

class SingletonEnforcer{}